home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Contributions / Olaf_Barthel / Tools / AmigaGuide / CheckGuide / Source / CheckGuide.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-21  |  32.5 KB  |  1,513 lines

  1. /*
  2.  * CheckGuide.c, A tool to check the consistency of AmigaGuide databases
  3.  *
  4.  * Copyright © 1997 by Olaf Barthel <olsen@sourcery.han.de>
  5.  * All Rights Reserved
  6.  *
  7.  * :ts=4
  8.  */
  9.  
  10. #include <exec/lists.h>
  11. #include <exec/nodes.h>
  12.  
  13. #include <dos/dosextens.h>
  14. #include <dos/rdargs.h>
  15.  
  16. #include <clib/exec_protos.h>
  17. #include <clib/dos_protos.h>
  18. #include <clib/alib_protos.h>
  19.  
  20. #ifdef __SASC
  21. #include <pragmas/exec_sysbase_pragmas.h>
  22. #include <pragmas/dos_pragmas.h>
  23. #endif /* __SASC */
  24.  
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <signal.h>
  29.  
  30. /****************************************************************************/
  31.  
  32. #define SAME    (0)
  33. #define NOT        !
  34. #define CANNOT    !
  35.  
  36. /****************************************************************************/
  37.  
  38. void FreeList(struct List *list);
  39. struct Node *FindIName(const struct List *list, const char *name);
  40. struct EntryNode *CreateNode(const char *name);
  41. BOOL IsNumber(const char *s);
  42. VOID CollectNodes(const char *file, struct List *list);
  43. struct DatabaseNode *RegisterFile(struct List *list, BPTR lock);
  44. struct DatabaseNode *LocateNode(const char *parentFileName, const char *thisFileName, int line, const char *linkFileName);
  45. void CheckGuide(const char *file, const char *parentFile, FILE *in);
  46. int main(int argc, char **argv);
  47.  
  48. /****************************************************************************/
  49.  
  50. STRPTR version = "$VER: CheckGuide 1.8 (21.8.97)";
  51.  
  52. /****************************************************************************/
  53.  
  54. extern struct Library *SysBase;
  55. extern struct Library *DOSBase;
  56.  
  57. /****************************************************************************/
  58.  
  59. struct EntryNode
  60. {
  61.     struct Node            Node;
  62.     long                line;
  63.     long                references;
  64.     struct EntryNode *    within;
  65. };
  66.  
  67. struct DatabaseNode
  68. {
  69.     struct Node            Node;
  70.     struct List            nodes;
  71.     BOOL                collected;
  72.     BOOL                checked;
  73. };
  74.  
  75. /****************************************************************************/
  76.  
  77. #define LINK        "@{"
  78. #define OPEN_BRACE    '{'
  79. #define CLOSE_BRACE    '}'
  80.  
  81. /****************************************************************************/
  82.  
  83. const char *keywords[][2] =
  84. {
  85.     "@database",        "1NAME/A",
  86.     "@author",            "1NAME/F",
  87.     "@(c)",                "1NAME/F",
  88.     "@$VER: ",            "1NAME/F",
  89.     "@master",            "1NAME/A",
  90.     "@font",            "1NAME/A,2SIZE/N/A",
  91.     "@index",            "1NAME/A",
  92.     "@help",            "1NAME/A",
  93.     "@onopen",            "1NAME/F",
  94.     "@onclose",            "1NAME/F",
  95.     "@proportional",    NULL,
  96.     "@wordwrap",        NULL,
  97.     "@smartwrap",        NULL,
  98.     "@node",            "1NAME/A,2TITLE",
  99.     "@dnode",            "1NAME/A,2TITLE",
  100.     "@remark",            NULL,
  101.     "@rem",                NULL,
  102.     "@title",            "1TITLE/A/F",
  103.     "@toc",                "1NAME/A",
  104.     "@macro",            "1NAME/A,2NAME/A",
  105.     "@prev",            "1NAME/A",
  106.     "@xref",            "1NAME/A",
  107.     "@next",            "1NAME/A",
  108.     "@width",            "1NAME/A/N",
  109.     "@height",            "1NAME/A/N",
  110.     "@tab",                "1NAME/A/N",
  111.     "@keywords",        "1KEYWORDS/A/M",
  112.     "@endnode",            NULL,
  113.     LINK,                "1LABEL/A,2COMMAND/A/F",
  114.     NULL
  115. };
  116.  
  117. /****************************************************************************/
  118.  
  119. struct List CheckedFileList;
  120. BOOL Recursive = FALSE;
  121. BOOL OnlyGuideFiles = FALSE;
  122. BOOL Warnings = TRUE;
  123.  
  124. /****************************************************************************/
  125.  
  126. void
  127. FreeList(struct List *list)
  128. {
  129.     struct Node *node;
  130.  
  131.     while((node = RemHead(list)) != NULL)
  132.         free(node);
  133. }
  134.  
  135. struct Node *
  136. FindIName(
  137.     const struct List *    list,
  138.     const char *        name)
  139. {
  140.     struct Node *node;
  141.  
  142.     for(node = list->lh_Head ; node->ln_Succ ; node = node->ln_Succ)
  143.     {
  144.         if(stricmp(node->ln_Name,name) == SAME)
  145.             return(node);
  146.     }
  147.  
  148.     return(NULL);
  149. }
  150.  
  151. struct EntryNode *
  152. CreateNode(const char *name)
  153. {
  154.     struct EntryNode * node;
  155.  
  156.     node = (struct EntryNode *)malloc(strlen(name)+1 + sizeof(*node));
  157.     if(node != NULL)
  158.     {
  159.         memset(node,0,strlen(name)+1 + sizeof(*node));
  160.         strcpy(node->Node.ln_Name = (char *)(node + 1),name);
  161.     }
  162.     else
  163.     {
  164.         perror("CheckGuide");
  165.         exit(RETURN_FAIL);
  166.     }
  167.  
  168.     return(node);
  169. }
  170.  
  171. /****************************************************************************/
  172.  
  173. BOOL
  174. IsNumber(const char *s)
  175. {
  176.     int len = strlen(s);
  177.  
  178.     if(len == 0)
  179.     {
  180.         return(FALSE);
  181.     }
  182.     else
  183.     {
  184.         int i;
  185.  
  186.         for(i = 0 ; i < len ; i++)
  187.         {
  188.             if(s[i] < '0' || s[i] > '9')
  189.                 return(FALSE);
  190.         }
  191.  
  192.         return(TRUE);
  193.     }
  194. }
  195.  
  196. /****************************************************************************/
  197.  
  198. VOID
  199. CollectNodes(
  200.     const char *    file,
  201.     struct List *    list)
  202. {
  203.     FILE *in;
  204.  
  205.     /* This file *must* exist. */
  206.     in = fopen(file,"r");
  207.     if(in != NULL)
  208.     {
  209.         static char buffer[1024];
  210.         int i,len,line;
  211.  
  212.         line = 0;
  213.  
  214.         /* Two characters less to allow for line termination characters. */
  215.         while(fgets(buffer,sizeof(buffer)-2,in) != NULL)
  216.         {
  217.             /* Strip trailing line feed. */
  218.             len = strlen(buffer);
  219.             if(len > 0 && buffer[len - 1] == '\n')
  220.                 buffer[--len] = '\0';
  221.  
  222.             /* If this is the first line, it must have the
  223.              * @database keyword in it (if this is an AmigaGuide
  224.              * database, that is).
  225.              */
  226.             line++;
  227.             if(line == 1 && strnicmp(buffer,"@database",9))
  228.             {
  229.                 const char *main = "main";
  230.                 struct Node *node;
  231.  
  232.                 /* A "main" node is always available, so to speak. */
  233.                 node = (struct Node *)malloc(sizeof(*node) + strlen(main)+1);
  234.                 if(node != NULL)
  235.                 {
  236.                     strcpy(node->ln_Name = (char *)(node + 1),main);
  237.                     AddTail(list,node);
  238.                 }
  239.                 else
  240.                 {
  241.                     perror("CheckGuide");
  242.                     exit(RETURN_FAIL);
  243.                 }
  244.  
  245.                 break;
  246.             }
  247.  
  248.             /* If this line carries a @node keyword, analyze
  249.              * it. We want to keep the node name.
  250.              */
  251.             if(strnicmp(buffer,"@node",5) == SAME)
  252.             {
  253.                 int quote = 0;
  254.                 BOOL gotNodeName = FALSE;
  255.                 char *skip = &buffer[5];
  256.  
  257.                 while(*skip == ' ' || *skip == '\t')
  258.                     skip++;
  259.  
  260.                 len = strlen(skip);
  261.  
  262.                 /* Flatten all escape characters. */
  263.                 for(i = 0 ; i < len ; i++)
  264.                 {
  265.                     if(skip[i] == '\\' && i < len-1)
  266.                     {
  267.                         skip[i] = '-';
  268.                         skip[i+1] = '-';
  269.                     }
  270.                 }
  271.  
  272.                 /* So the following search will always terminate. */
  273.                 strcat(skip," ");
  274.                 len++;
  275.  
  276.                 /* Look for the node name. */
  277.                 for(i = 0 ; i < len ; i++)
  278.                 {
  279.                     if(skip[i] == '\"')
  280.                         quote ^= 1;
  281.  
  282.                     /* The search stops at a blank space. */
  283.                     if(skip[i] == ' ' || skip[i] == '\t')
  284.                     {
  285.                         if(quote == 0)
  286.                         {
  287.                             skip[i] = '\0';
  288.                             gotNodeName = TRUE;
  289.                             break;
  290.                         }
  291.                     }
  292.                 }
  293.  
  294.                 /* If we got a node name, check if it contains
  295.                  * space characters (it must not).
  296.                  */
  297.                 if(gotNodeName)
  298.                 {
  299.                     len = strlen(skip);
  300.  
  301.                     for(i = 0 ; i < len ; i++)
  302.                     {
  303.                         if(skip[i] == ' ' || skip[i] == '\t')
  304.                         {
  305.                             gotNodeName = FALSE;
  306.                             break;
  307.                         }
  308.                     }
  309.                 }
  310.  
  311.                 /* If this is still a valid node name, strip
  312.                  * any quote characters and add it to the list.
  313.                  */
  314.                 if(gotNodeName)
  315.                 {
  316.                     struct Node *node;
  317.                     int j;
  318.  
  319.                     for(i = 0, j = 0 ; i < len ; i++)
  320.                     {
  321.                         if(skip[i] != '\"')
  322.                             buffer[j++] = skip[i];
  323.                     }
  324.  
  325.                     buffer[j] = '\0';
  326.  
  327.                     node = (struct Node *)malloc(sizeof(*node) + strlen(buffer)+1);
  328.                     if(node != NULL)
  329.                     {
  330.                         strcpy(node->ln_Name = (char *)(node + 1),buffer);
  331.                         AddTail(list,node);
  332.                     }
  333.                     else
  334.                     {
  335.                         perror("CheckGuide");
  336.                         exit(RETURN_FAIL);
  337.                     }
  338.                 }
  339.             }
  340.         }
  341.  
  342.         fclose(in);
  343.     }
  344. }
  345.  
  346. struct DatabaseNode *
  347. RegisterFile(
  348.     struct List *    list,
  349.     BPTR            lock)
  350. {
  351.     char localBuffer[400];
  352.     struct DatabaseNode * result = NULL;
  353.  
  354.     if(NameFromLock(lock,localBuffer,sizeof(localBuffer)))
  355.     {
  356.         result = (struct DatabaseNode *)FindIName(list,localBuffer);
  357.         if(result == NULL)
  358.         {
  359.             result = (struct DatabaseNode *)malloc(sizeof(*result) + strlen(localBuffer)+1);
  360.             if(result != NULL)
  361.             {
  362.                 strcpy(result->Node.ln_Name = (char *)(result + 1),localBuffer);
  363.                 NewList(&result->nodes);
  364.                 result->checked = FALSE;
  365.                 result->collected = FALSE;
  366.  
  367.                 AddTail(list,(struct Node *)result);
  368.             }
  369.             else
  370.             {
  371.                 perror("CheckGuide");
  372.                 exit(RETURN_FAIL);
  373.             }
  374.         }
  375.     }
  376.  
  377.     return(result);
  378. }
  379.  
  380. struct DatabaseNode *
  381. LocateNode(
  382.     const char *    parentFileName,
  383.     const char *    thisFileName,
  384.     int                line,
  385.     const char *    linkFileName)
  386. {
  387.     char fileName[400];
  388.     char *nodeName;
  389.     struct DatabaseNode *result = NULL;
  390.  
  391.     nodeName = FilePart((STRPTR)linkFileName);
  392.     if(nodeName != linkFileName)
  393.     {
  394.         struct Process *thisProcess = (struct Process *)FindTask(NULL);
  395.         APTR oldPtr = thisProcess->pr_WindowPtr;
  396.         BPTR lock;
  397.         BOOL relativePath = FALSE;
  398.  
  399.         strcpy(fileName,linkFileName);
  400.         *PathPart(fileName) = '\0';
  401.  
  402.         thisProcess->pr_WindowPtr = (APTR)-1;
  403.  
  404.         lock = Lock(fileName,SHARED_LOCK);
  405.         if(lock == NULL)
  406.         {
  407.             strcpy(fileName,parentFileName);
  408.             *PathPart(fileName) = '\0';
  409.             if(AddPart(fileName,(STRPTR)linkFileName,sizeof(fileName)))
  410.             {
  411.                 *PathPart(fileName) = '\0';
  412.  
  413.                 lock = Lock(fileName,SHARED_LOCK);
  414.                 relativePath = TRUE;
  415.             }
  416.         }
  417.  
  418.         thisProcess->pr_WindowPtr = oldPtr;
  419.  
  420.         if(lock != NULL)
  421.         {
  422.             struct DatabaseNode *node;
  423.  
  424.             node = RegisterFile(&CheckedFileList,lock);
  425.             result = node;
  426.  
  427.             UnLock(lock);
  428.  
  429.             if(relativePath && Warnings)
  430.                 printf("%s:%d:File found in relative path only \"%s\"\n",thisFileName,line,fileName);
  431.  
  432.             if(node != NULL)
  433.             {
  434.                 if(NOT node->collected)
  435.                 {
  436.                     CollectNodes(node->Node.ln_Name,&node->nodes);
  437.                     node->collected = TRUE;
  438.                 }
  439.  
  440.                 if(CANNOT FindIName(&node->nodes,nodeName))
  441.                 {
  442.                     result = NULL;
  443.                 }
  444.             }
  445.         }
  446.     }
  447.  
  448.     return(result);
  449. }
  450.  
  451. /****************************************************************************/
  452.  
  453. void
  454. CheckGuide(
  455.     const char *    file,
  456.     const char *    parentFile,
  457.     FILE *            in)
  458. {
  459.     static char buffer[1024];
  460.     static char localBuffer[1000];
  461.     int line,len;
  462.     struct EntryNode *lastNode = NULL;
  463.     struct EntryNode *node, *mainFound;
  464.     char plainName[400];
  465.     int i,j;
  466.     char *suffix = "guide";
  467.     struct List NodeList;
  468.     struct List IndexList;
  469.     struct List TocList;
  470.     struct RDArgs *rdargs;
  471.     int underlineCol = -1,underlineRow = -1;
  472.     int boldCol = -1,boldRow = -1;
  473.     int italicsCol = -1,italicsRow = -1;
  474.  
  475.     NewList(&NodeList);
  476.     NewList(&IndexList);
  477.     NewList(&TocList);
  478.  
  479.     strcpy(plainName,FilePart((STRPTR)file));
  480.     for(j = strlen(plainName) - 1 ; j >= 0 ; j--)
  481.     {
  482.         if(stricmp(&plainName[j],".hyper") == SAME)
  483.         {
  484.             if(Warnings)
  485.                 printf("%s:%d:File uses obsolete .hyper name suffix\n",file,1);
  486.  
  487.             plainName[j] = '\0';
  488.             suffix = &plainName[j+1];
  489.             break;
  490.         }
  491.  
  492.         if(stricmp(&plainName[j],".guide") == SAME)
  493.         {
  494.             plainName[j] = '\0';
  495.             suffix = &plainName[j+1];
  496.             break;
  497.         }
  498.     }
  499.  
  500.     line = 0;
  501.  
  502.     while(fgets(buffer,sizeof(buffer)-1,in) != NULL)
  503.     {
  504.         line++;
  505.  
  506.         len = strlen(buffer);
  507.         if(len > 0 && buffer[len - 1] == '\n')
  508.             buffer[--len] = '\0';
  509.  
  510.         if(line == 1)
  511.         {
  512.             if(strnicmp(buffer,"@database",9))
  513.             {
  514.                 if(OnlyGuideFiles && Recursive)
  515.                     return;
  516.  
  517.                 printf("%s:%d:First line must contain @database keyword\n",file,line);
  518.             }
  519.         }
  520.  
  521.         for(i = 0 ; i < len ; i++)
  522.         {
  523.             if(buffer[i] == '@' && buffer[i+1] == '@')
  524.             {
  525.                 buffer[i] = buffer[i+1] = ' ';
  526.             }
  527.  
  528.             if(buffer[i] == '\\' && i < len-1)
  529.             {
  530.                 buffer[i] = buffer[i+1] = '-';
  531.             }
  532.         }
  533.  
  534.         if(buffer[0] == '@')
  535.         {
  536.             char const *found = NULL;
  537.  
  538.             for(i = 0 ; keywords[i][0] != NULL ; i++)
  539.             {
  540.                 if(strnicmp(buffer,keywords[i][0],strlen(keywords[i][0])) == SAME)
  541.                 {
  542.                     found = keywords[i][0];
  543.                     break;
  544.                 }
  545.             }
  546.  
  547.             if(NOT found)
  548.             {
  549.                 char key[40];
  550.  
  551.                 strncpy(key,buffer,19);
  552.                 key[19] = '\0';
  553.                 printf("%s:%d:Unknown keyword \"%s\"\n",file,line,key);
  554.             }
  555.             else
  556.             {
  557.                 if(keywords[i][1] != NULL)
  558.                 {
  559.                     long args[2] = { NULL,NULL };
  560.  
  561.                     signal(SIGINT,SIG_IGN);
  562.  
  563.                     rdargs = AllocDosObjectTagList(DOS_RDARGS,NULL);
  564.                     if(rdargs != NULL)
  565.                     {
  566.                         char *rest;
  567.                         int k;
  568.  
  569.                         strcat(buffer,"\n");
  570.  
  571.                         rest = buffer + strlen(keywords[i][0]);
  572.  
  573.                         while(*rest == ' ')
  574.                             rest++;
  575.  
  576.                         rdargs->RDA_Source.CS_Buffer    = rest;
  577.                         rdargs->RDA_Source.CS_Length    = strlen(rdargs->RDA_Source.CS_Buffer);
  578.                         rdargs->RDA_Source.CS_CurChr    = 0;
  579.                         rdargs->RDA_Flags                = RDAF_NOPROMPT;
  580.  
  581.                         for(k = 0 ; k < strlen(rest) ; k++)
  582.                         {
  583.                             if(rest[k] == '*')    /* This confuses the ReadArgs() parser. */
  584.                                 rest[k] = '+';
  585.                         }
  586.  
  587.                         if(ReadArgs((char *)keywords[i][1],args,rdargs))
  588.                         {
  589.                             if(strcmp(found,"@node") == SAME || strcmp(found,"@dnode") == SAME)
  590.                             {
  591.                                 if(lastNode != NULL)
  592.                                 {
  593.                                     printf("%s:%d:Unbalanced @node\n",file,lastNode->line);
  594.                                 }
  595.  
  596.                                 lastNode = CreateNode((char *)args[0]);
  597.                                 if(lastNode != NULL)
  598.                                 {
  599.                                     struct Node *node;
  600.  
  601.                                     lastNode->line = line;
  602.  
  603.                                     for(node = NodeList.lh_Head ; node->ln_Succ ; node = node->ln_Succ)
  604.                                     {
  605.                                         if(stricmp(node->ln_Name,(char *)args[0]) == SAME)
  606.                                         {
  607.                                             printf("%s:%d:Duplicate @node \"%s\" (see line %d)\n",file,line,node->ln_Name,((struct EntryNode *)lastNode)->line);
  608.                                             break;
  609.                                         }
  610.                                     }
  611.  
  612.                                     AddTail(&NodeList,(struct Node *)lastNode);
  613.                                 }
  614.                             }
  615.  
  616.                             if(strcmp(found,"@database") == SAME)
  617.                             {
  618.                                 char otherPlainName[400];
  619.                                 char *otherSuffix = "guide";
  620.                                 int j;
  621.  
  622.                                 strcpy(otherPlainName,FilePart((char *)args[0]));
  623.                                 for(j = strlen(otherPlainName) - 1 ; j >= 0 ; j--)
  624.                                 {
  625.                                     if(stricmp(&otherPlainName[j],".guide") == SAME)
  626.                                     {
  627.                                         otherPlainName[j] = '\0';
  628.                                         otherSuffix = &otherPlainName[j+1];
  629.                                         break;
  630.                                     }
  631.  
  632.                                     if(stricmp(&otherPlainName[j],".hyper") == SAME)
  633.                                     {
  634.                                         otherPlainName[j] = '\0';
  635.                                         otherSuffix = &otherPlainName[j+1];
  636.  
  637.                                         if(Warnings)
  638.                                             printf("%s:%d:Database name uses obsolete .hyper suffix\n",file,line,found);
  639.  
  640.                                         break;
  641.                                     }
  642.                                 }
  643.  
  644.                                 if(Warnings)
  645.                                 {
  646.                                     if(stricmp(suffix,otherSuffix))
  647.                                         printf("%s:%d:Database \"%s\" and file name \"%s\" suffixes do not match\n",file,line,suffix,otherSuffix);
  648.                                     else
  649.                                     {
  650.                                         if(stricmp(otherPlainName,plainName))
  651.                                             printf("%s:%d:Database \"%s\" and file name \"%s\" do not match\n",file,line,otherPlainName,plainName);
  652.                                     }
  653.  
  654.                                     if(FilePart((STRPTR)args[0]) != (STRPTR)args[0])
  655.                                         printf("%s:%d:Database name \"%s\" contains path specifiers\n",file,line,args[0]);
  656.                                 }
  657.                             }
  658.  
  659.                             if(strcmp(found,"@toc") == SAME)
  660.                             {
  661.                                 struct EntryNode *node;
  662.  
  663.                                 node = CreateNode((char *)args[0]);
  664.                                 if(node != NULL)
  665.                                 {
  666.                                     node->line = line;
  667.                                     node->within = lastNode;
  668.  
  669.                                     AddTail(&TocList,(struct Node *)node);
  670.                                 }
  671.                             }
  672.  
  673.                             if(strcmp(found,"@index") == SAME)
  674.                             {
  675.                                 struct EntryNode *node;
  676.  
  677.                                 node = CreateNode((char *)args[0]);
  678.                                 if(node != NULL)
  679.                                 {
  680.                                     node->line = line;
  681.                                     node->within = lastNode;
  682.  
  683.                                     AddTail(&IndexList,(struct Node *)node);
  684.                                 }
  685.                             }
  686.                         }
  687.                         else
  688.                         {
  689.                             if(strcmp(found,LINK))
  690.                             {
  691.                                 char errorBuffer[400];
  692.  
  693.                                 Fault(IoErr(),NULL,errorBuffer,sizeof(errorBuffer));
  694.                                 printf("%s:%d:%s: %s\n",file,line,found,errorBuffer);
  695.                             }
  696.                         }
  697.  
  698.                         FreeArgs(rdargs);
  699.                         FreeDosObject(DOS_RDARGS,rdargs);
  700.                     }
  701.  
  702.                     signal(SIGINT,SIG_DFL);
  703.                 }
  704.  
  705.                 if(strcmp(found,"@endnode") == SAME)
  706.                 {
  707.                     if(lastNode != NULL)
  708.                     {
  709.                         lastNode = NULL;
  710.                     }
  711.                     else
  712.                     {
  713.                         printf("%s:%d:Unbalanced @endnode\n",file,line);
  714.                     }
  715.                 }
  716.  
  717.                 if(strcmp(found,LINK) == SAME)
  718.                 {
  719.                     int i,quote = 0,brace = 1;
  720.  
  721.                     for(i = 2 ; i < len ; i++)
  722.                     {
  723.                         if(buffer[i] == '\"')
  724.                         {
  725.                             quote ^= 1;
  726.                         }
  727.                         else
  728.                         {
  729.                             if(quote == 0)
  730.                             {
  731.                                 if(buffer[i] == OPEN_BRACE)    /* open brace */
  732.                                     brace++;
  733.  
  734.                                 if(buffer[i] == CLOSE_BRACE)    /* closing brace */
  735.                                     brace--;
  736.  
  737.                                 if(brace == 0)
  738.                                     break;
  739.                             }
  740.                         }
  741.                     }
  742.  
  743.                     if(brace > 0)
  744.                         printf("%s:%d:Missing closing brace in button declaration\n",file,line);
  745.  
  746.                     if(brace < 0)
  747.                         printf("%s:%d:Unbalanced open brace in button declaration\n",file,line);
  748.  
  749.                     if(quote > 0)
  750.                         printf("%s:%d:Missing quote in button declaration\n",file,line);
  751.                 }
  752.             }
  753.         }
  754.     }
  755.  
  756.     fseek(in,0,SEEK_SET);
  757.  
  758.     line = 0;
  759.  
  760.     while(fgets(buffer,sizeof(buffer)-1,in) != NULL)
  761.     {
  762.         line++;
  763.  
  764.         len = strlen(buffer);
  765.         if(len > 0 && buffer[len - 1] == '\n')
  766.             buffer[--len] = '\0';
  767.  
  768.         if(len > 0)
  769.         {
  770.             int i,quote = 0;
  771.  
  772.             for(i = 0 ; i < len ; i++)
  773.             {
  774.                 if(buffer[i] == '@' && buffer[i+1] == '@')
  775.                 {
  776.                     if(Warnings)
  777.                         printf("%s:%d:\"%c\" character escaped in column %d\n",file,line,buffer[i],i+1);
  778.  
  779.                     buffer[i] = buffer[i+1] = ' ';
  780.                 }
  781.  
  782.                 if(buffer[i] == '\\' && i < len-1)
  783.                 {
  784.                     if(Warnings)
  785.                         printf("%s:%d:\"\\%c\" escape sequence in column %d\n",file,line,buffer[i+1],i+1);
  786.  
  787.                     buffer[i] = buffer[i+1] = '-';
  788.                 }
  789.             }
  790.  
  791.             for(i = 0 ; i < len ; )
  792.             {
  793. /*                if(buffer[i] == '\"')*/
  794. /*                    quote ^= 1;*/
  795.  
  796.                 if(!quote && buffer[i] == '@' && buffer[i+1] == OPEN_BRACE)
  797.                 {
  798.                     int j,quote = 0,brace = 1,total;
  799.  
  800.                     buffer[i] = ' ';
  801.  
  802.                     for(j = i+2, total = 2 ; j < len ; j++, total++)
  803.                     {
  804.                         if(buffer[j] == '\"')
  805.                         {
  806.                             quote ^= 1;
  807.                         }
  808.                         else
  809.                         {
  810.                             if(quote == 0)
  811.                             {
  812.                                 if(buffer[j] == OPEN_BRACE)
  813.                                     brace++;
  814.  
  815.                                 if(buffer[j] == CLOSE_BRACE)
  816.                                     brace--;
  817.  
  818.                                 if(brace == 0)
  819.                                 {
  820.                                     total++;
  821.                                     break;
  822.                                 }
  823.                             }
  824.                         }
  825.                     }
  826.  
  827.                     if(brace == 0 && quote == 0)
  828.                     {
  829.                         static char *style[] =
  830.                         {
  831.                             "amigaguide",
  832.                             "b",
  833.                             "body",
  834.                             "cleartabs",
  835.                             "code",
  836.                             "fontn",
  837.                             "heading",
  838.                             "i",
  839.                             "jcenter",
  840.                             "jleft",
  841.                             "jright",
  842.                             "lindent",
  843.                             "line",
  844.                             "mono",
  845.                             "par",
  846.                             "pard",
  847.                             "pari",
  848.                             "plain",
  849.                             "prop",
  850.                             "settabs",
  851.                             "tab",
  852.                             "u",
  853.                             "ub",
  854.                             "ui",
  855.                             "uu",
  856.                             NULL
  857.                         };
  858.                         BOOL known = FALSE;
  859.                         int k,len;
  860.                         char *skip;
  861.  
  862.                         skip = &buffer[i+2];
  863.                         len = total-3;
  864.  
  865.                         while(*skip == ' ' && len > 0)
  866.                         {
  867.                             skip++;
  868.                             len--;
  869.                         }
  870.  
  871.                         if(len > 0)
  872.                             strncpy(localBuffer,skip,len);
  873.                         localBuffer[len] = '\0';
  874.  
  875.                         for(k = 0 ; style[k] != NULL ; k++)
  876.                         {
  877.                             if(stricmp(localBuffer,style[k]) == SAME)
  878.                             {
  879.                                 if(stricmp(style[k],"u") == SAME)
  880.                                 {
  881.                                     if(underlineCol != -1)
  882.                                         printf("%s:%d:Unbalanced @{%s} in column %d\n",file,underlineRow,style[k],underlineCol);
  883.  
  884.                                     underlineCol = i+1;
  885.                                     underlineRow = line;
  886.                                 }
  887.  
  888.                                 if(stricmp(style[k],"uu") == SAME)
  889.                                 {
  890.                                     if(underlineCol == -1)
  891.                                         printf("%s:%d:Command @{%s} in column %d has no effect\n",file,line,style[k],i+1);
  892.  
  893.                                     underlineCol = -1;
  894.                                     underlineRow = -1;
  895.                                 }
  896.  
  897.                                 if(stricmp(style[k],"b") == SAME)
  898.                                 {
  899.                                     if(boldCol != -1)
  900.                                         printf("%s:%d:Unbalanced @{%s} in column %d\n",file,boldRow,style[k],boldCol);
  901.  
  902.                                     boldCol = i+1;
  903.                                     boldRow = line;
  904.                                 }
  905.  
  906.                                 if(stricmp(style[k],"ub") == SAME)
  907.                                 {
  908.                                     if(boldCol == -1)
  909.                                         printf("%s:%d:Command @{%s} in column %d has no effect\n",file,line,style[k],i+1);
  910.  
  911.                                     boldCol = -1;
  912.                                     boldRow = -1;
  913.                                 }
  914.  
  915.                                 if(stricmp(style[k],"i") == SAME)
  916.                                 {
  917.                                     if(italicsCol != -1)
  918.                                         printf("%s:%d:Unbalanced @{%s} in column %d\n",file,italicsRow,style[k],italicsCol);
  919.  
  920.                                     italicsCol = i+1;
  921.                                     italicsRow = line;
  922.                                 }
  923.  
  924.                                 if(stricmp(style[k],"ui") == SAME)
  925.                                 {
  926.                                     if(italicsCol == -1)
  927.                                         printf("%s:%d:Command @{%s} in column %d has no effect\n",file,line,style[k],i+1);
  928.  
  929.                                     italicsCol = -1;
  930.                                     italicsRow = -1;
  931.                                 }
  932.  
  933.                                 known = TRUE;
  934.                                 break;
  935.                             }
  936.                         }
  937.  
  938.                         if(NOT known)
  939.                         {
  940.                             static char *colourControl[] =
  941.                             {
  942.                                 "fg",
  943.                                 "apen",
  944.                                 "bg",
  945.                                 "bpen",
  946.                                 NULL
  947.                             };
  948.  
  949.                             char *rest = NULL;
  950.  
  951.                             for(k = 0 ; colourControl[k] != NULL ; k++)
  952.                             {
  953.                                 if(strnicmp(localBuffer,colourControl[k],strlen(colourControl[k])) == SAME)
  954.                                 {
  955.                                     rest = &localBuffer[strlen(colourControl[k])];
  956.                                     break;
  957.                                 }
  958.                             }
  959.  
  960.                             if(rest != NULL)
  961.                             {
  962.                                 known = TRUE;
  963.  
  964.                                 if(rest[0] != ' ')
  965.                                     printf("%s:%d:Invalid colour control string \"%s\"\n",file,line,rest);
  966.                                 else
  967.                                 {
  968.                                     static char *pens[] =
  969.                                     {
  970.                                         "text",
  971.                                         "shine",
  972.                                         "shadow",
  973.                                         "fill",
  974.                                         "filltext",
  975.                                         "back",
  976.                                         "background",
  977.                                         "highlight",
  978.                                         NULL
  979.                                     };
  980.  
  981.                                     BOOL found = FALSE;
  982.  
  983.                                     while(*rest == ' ')
  984.                                         rest++;
  985.  
  986.                                     for(k = 0 ; pens[k] != NULL ; k++)
  987.                                     {
  988.                                         if(stricmp(rest,pens[k]) == SAME)
  989.                                         {
  990.                                             found = TRUE;
  991.                                             break;
  992.                                         }
  993.                                     }
  994.  
  995.                                     if(NOT found)
  996.                                         printf("%s:%d:Invalid colour \"%s\"\n",file,line,rest);
  997.                                 }
  998.                             }
  999.                         }
  1000.  
  1001.                         signal(SIGINT,SIG_IGN);
  1002.  
  1003.                         if(NOT known)
  1004.                             rdargs = AllocDosObjectTagList(DOS_RDARGS,NULL);
  1005.                         else
  1006.                             rdargs = NULL;
  1007.  
  1008.                         if(rdargs != NULL)
  1009.                         {
  1010.                             long args[4] = { NULL,NULL,NULL,NULL };
  1011.                             int k;
  1012.  
  1013.                             strcat(localBuffer,"\n");
  1014.  
  1015.                             rdargs->RDA_Source.CS_Buffer    = localBuffer;
  1016.                             rdargs->RDA_Source.CS_Length    = strlen(rdargs->RDA_Source.CS_Buffer);
  1017.                             rdargs->RDA_Source.CS_CurChr    = 0;
  1018.                             rdargs->RDA_Flags                = RDAF_NOPROMPT;
  1019.  
  1020.                             for(k = 0 ; k < strlen(localBuffer) ; k++)
  1021.                             {
  1022.                                 if(localBuffer[k] == '*')    /* This confuses the ReadArgs() parser. */
  1023.                                     localBuffer[k] = '+';
  1024.                             }
  1025.  
  1026.                             if(ReadArgs("1TEXT/A,2COMMAND/A,3ARG,4ARG",args,rdargs))
  1027.                             {
  1028.                                 char *name = (char *)args[1];
  1029.                                 char *arg1 = (char *)args[2];
  1030.                                 char *arg2 = (char *)args[3];
  1031.  
  1032.                                 if(localBuffer[0] != '\"' || localBuffer[1 + strlen((char *)args[0])] != '\"')
  1033.                                     printf("%s:%d:Button label \"%s\" must be enclosed in quotes\n",file,line,args[0]);
  1034.  
  1035.                                 if(stricmp(name,"alink") == SAME)
  1036.                                 {
  1037.                                     if(arg1 == NULL || (arg1 != NULL && *arg1 == '\0'))
  1038.                                         printf("%s:%d:ALINK node name required\n",file,line);
  1039.                                     else
  1040.                                     {
  1041.                                         struct EntryNode *found;
  1042.  
  1043.                                         found = (struct EntryNode *)FindIName(&NodeList,arg1);
  1044.  
  1045.                                         if(found)
  1046.                                         {
  1047.                                             found->references++;
  1048.                                         }
  1049.                                         else
  1050.                                         {
  1051.                                             struct DatabaseNode *otherNode;
  1052.  
  1053.                                             otherNode = LocateNode(parentFile,file,line,(char *)arg1);
  1054.                                             if(otherNode != NULL && Recursive && !otherNode->checked)
  1055.                                             {
  1056.                                                 FILE *in;
  1057.  
  1058.                                                 in = fopen(otherNode->Node.ln_Name,"r");
  1059.                                                 if(in != NULL)
  1060.                                                 {
  1061.                                                     otherNode->checked = TRUE;
  1062.                                                     CheckGuide(otherNode->Node.ln_Name,parentFile,in);
  1063.  
  1064.                                                     fclose(in);
  1065.                                                 }
  1066.                                                 else
  1067.                                                 {
  1068.                                                     perror(otherNode->Node.ln_Name);
  1069.                                                 }
  1070.                                             }
  1071.  
  1072.                                             if(otherNode == NULL)
  1073.                                                 printf("%s:%d:Reference to undefined node \"%s\"\n",file,line,arg1);
  1074.                                         }
  1075.                                     }
  1076.  
  1077.                                     if(arg2 != NULL)
  1078.                                     {
  1079.                                         if(!IsNumber(arg2))
  1080.                                             printf("%s:%d:ALINK line number invalid\n",file,line);
  1081.                                     }
  1082.                                 }
  1083.                                 else if (!stricmp(name,"close"))
  1084.                                 {
  1085.                                     if(arg1 != NULL && arg2 != NULL)
  1086.                                         printf("%s:%d:Too many arguments for CLOSE command\n",file,line);
  1087.                                 }
  1088.                                 else if (!stricmp(name,"link"))
  1089.                                 {
  1090.                                     if(arg1 == NULL || (arg1 != NULL && *arg1 == '\0'))
  1091.                                         printf("%s:%d:LINK node name required\n",file,line);
  1092.                                     else
  1093.                                     {
  1094.                                         struct EntryNode *found;
  1095.  
  1096.                                         found = (struct EntryNode *)FindIName(&NodeList,arg1);
  1097.  
  1098.                                         if(found)
  1099.                                         {
  1100.                                             found->references++;
  1101.                                         }
  1102.                                         else
  1103.                                         {
  1104.                                             struct DatabaseNode *otherNode;
  1105.  
  1106.                                             otherNode = LocateNode(parentFile,file,line,(char *)arg1);
  1107.                                             if(otherNode != NULL && Recursive && !otherNode->checked)
  1108.                                             {
  1109.                                                 FILE *in;
  1110.  
  1111.                                                 in = fopen(otherNode->Node.ln_Name,"r");
  1112.                                                 if(in != NULL)
  1113.                                                 {
  1114.                                                     otherNode->checked = TRUE;
  1115.                                                     CheckGuide(otherNode->Node.ln_Name,parentFile,in);
  1116.  
  1117.                                                     fclose(in);
  1118.                                                 }
  1119.                                                 else
  1120.                                                 {
  1121.                                                     perror(otherNode->Node.ln_Name);
  1122.                                                 }
  1123.                                             }
  1124.  
  1125.                                             if(otherNode == NULL)
  1126.                                                 printf("%s:%d:Reference to undefined node \"%s\"\n",file,line,arg1);
  1127.                                         }
  1128.                                     }
  1129.  
  1130.                                     if(arg2 != NULL)
  1131.                                     {
  1132.                                         if(!IsNumber(arg2))
  1133.                                             printf("%s:%d:LINK line number invalid\n",file,line);
  1134.                                     }
  1135.                                 }
  1136.                                 else if (!stricmp(name,"rx"))
  1137.                                 {
  1138.                                     if(arg1 == NULL || (arg1 != NULL && *arg1 == '\0'))
  1139.                                         printf("%s:%d:RX command required\n",file,line);
  1140.                                 }
  1141.                                 else if (!stricmp(name,"rxs"))
  1142.                                 {
  1143.                                     if(arg1 == NULL || (arg1 != NULL && *arg1 == '\0'))
  1144.                                         printf("%s:%d:RXS command required\n",file,line);
  1145.                                 }
  1146.                                 else if (!stricmp(name,"system"))
  1147.                                 {
  1148.                                     if(arg1 == NULL || (arg1 != NULL && *arg1 == '\0'))
  1149.                                         printf("%s:%d:SYSTEM command required\n",file,line);
  1150.                                 }
  1151.                                 else if (!stricmp(name,"quit"))
  1152.                                 {
  1153.                                     if(arg1 != NULL && arg2 != NULL)
  1154.                                         printf("%s:%d:Too many arguments for QUIT command\n",file,line);
  1155.                                 }
  1156.                                 else
  1157.                                 {
  1158.                                     printf("%s:%d:Unknown link command \"%s\"\n",file,line,name);
  1159.                                 }
  1160.                             }
  1161.                             else
  1162.                             {
  1163.                                 char errorBuffer[400];
  1164.  
  1165.                                 Fault(IoErr(),NULL,errorBuffer,sizeof(errorBuffer));
  1166.                                 printf("%s:%d:link: %s\n",file,line,errorBuffer);
  1167.                             }
  1168.  
  1169.                             FreeArgs(rdargs);
  1170.                             FreeDosObject(DOS_RDARGS,rdargs);
  1171.                         }
  1172.  
  1173.                         signal(SIGINT,SIG_DFL);
  1174.                     }
  1175.  
  1176.                     if(quote > 0)
  1177.                     {
  1178.                         printf("%s:%d:Unbalanced quote in button declaration at column %d\n",file,line,i+1);
  1179.                     }
  1180.  
  1181.                     if(brace > 0)
  1182.                     {
  1183.                         printf("%s:%d:Unbalanced brace in button declaration at column %d\n",file,line,i+1);
  1184.                     }
  1185.  
  1186.                     i += total;
  1187.                 }
  1188.                 else
  1189.                 {
  1190.                     if(!quote && buffer[i] == '@')
  1191.                     {
  1192.                         int j;
  1193.                         char const *found = NULL;
  1194.  
  1195.                         for(j = 0 ; keywords[j][0] != NULL ; j++)
  1196.                         {
  1197.                             if(strnicmp(&buffer[i],keywords[j][0],strlen(keywords[j][0])) == SAME)
  1198.                             {
  1199.                                 found = keywords[j][0];
  1200.                                 break;
  1201.                             }
  1202.                         }
  1203.  
  1204.                         if(found)
  1205.                             buffer[i] = ' ';
  1206.  
  1207.                         if(found && i > 0)
  1208.                         {
  1209.                             printf("%s:%d:Command \"%s\" has no effect\n",file,line,found);
  1210.                         }
  1211.  
  1212.                         if(found && i == 0)
  1213.                         {
  1214.                             if(strcmp(found,"@next") == SAME || strcmp(found,"@prev") == SAME)
  1215.                             {
  1216.                                 STRPTR nodeName = NULL;
  1217.                                 char *skip;
  1218.  
  1219.                                 skip = &buffer[strlen(found)];
  1220.                                 while(*skip == ' ')
  1221.                                     skip++;
  1222.  
  1223.                                 signal(SIGINT,SIG_IGN);
  1224.  
  1225.                                 rdargs = AllocDosObjectTagList(DOS_RDARGS,NULL);
  1226.                                 if(rdargs != NULL)
  1227.                                 {
  1228.                                     int k;
  1229.  
  1230.                                     strcat(skip,"\n");
  1231.  
  1232.                                     rdargs->RDA_Source.CS_Buffer    = skip;
  1233.                                     rdargs->RDA_Source.CS_Length    = strlen(rdargs->RDA_Source.CS_Buffer);
  1234.                                     rdargs->RDA_Source.CS_CurChr    = 0;
  1235.                                     rdargs->RDA_Flags                = RDAF_NOPROMPT;
  1236.  
  1237.                                     for(k = 0 ; k < strlen(skip) ; k++)
  1238.                                     {
  1239.                                         if(skip[k] == '*')    /* This confuses the ReadArgs() parser. */
  1240.                                             skip[k] = '+';
  1241.                                     }
  1242.  
  1243.                                     if(ReadArgs("1NODE/A",(LONG *)&nodeName,rdargs))
  1244.                                     {
  1245.                                         struct EntryNode *node;
  1246.  
  1247.                                         node = (struct EntryNode *)FindIName(&NodeList,nodeName);
  1248.                                         if(node != NULL)
  1249.                                         {
  1250.                                             node->references++;
  1251.                                         }
  1252.                                         else
  1253.                                         {
  1254.                                             struct DatabaseNode *otherNode;
  1255.  
  1256.                                             otherNode = LocateNode(parentFile,file,line,nodeName);
  1257.                                             if(otherNode != NULL && Recursive && !otherNode->checked)
  1258.                                             {
  1259.                                                 FILE *in;
  1260.  
  1261.                                                 in = fopen(otherNode->Node.ln_Name,"r");
  1262.                                                 if(in != NULL)
  1263.                                                 {
  1264.                                                     otherNode->checked = TRUE;
  1265.                                                     CheckGuide(otherNode->Node.ln_Name,parentFile,in);
  1266.  
  1267.                                                     fclose(in);
  1268.                                                 }
  1269.                                                 else
  1270.                                                 {
  1271.                                                     perror(otherNode->Node.ln_Name);
  1272.                                                 }
  1273.                                             }
  1274.  
  1275.                                             if(otherNode == NULL)
  1276.                                                 printf("%s:%d:%s references undefined node \"%s\"\n",file,line,found,nodeName);
  1277.                                         }
  1278.                                     }
  1279.                                     else
  1280.                                     {
  1281.                                         char errorBuffer[400];
  1282.  
  1283.                                         Fault(IoErr(),NULL,errorBuffer,sizeof(errorBuffer));
  1284.                                         printf("%s:%d:%s: %s\n",file,line,found,errorBuffer);
  1285.                                     }
  1286.  
  1287.                                     FreeArgs(rdargs);
  1288.                                     FreeDosObject(DOS_RDARGS,rdargs);
  1289.                                 }
  1290.  
  1291.                                 signal(SIGINT,SIG_DFL);
  1292.                             }
  1293.                         }
  1294.  
  1295.                         if(NOT found && buffer[i+1] == ' ')
  1296.                         {
  1297.                             char *rest = &buffer[i+1];
  1298.  
  1299.                             while(*rest == ' ')
  1300.                                 rest++;
  1301.  
  1302.                             if(*rest == OPEN_BRACE)
  1303.                                 printf("%s:%d:Incomplete/invalid link declaration\n",file,line);
  1304.                         }
  1305.                     }
  1306.  
  1307.                     i++;
  1308.                 }
  1309.             }
  1310.  
  1311.             for(i = 0 ; i < len ; i++)
  1312.             {
  1313.                 if(buffer[i] == '@' || buffer[i] == '\\')
  1314.                     printf("%s:%d:Single \"%c\" character in column %d\n",file,line,buffer[i],i + 1);
  1315.             }
  1316.         }
  1317.     }
  1318.  
  1319.     if(underlineCol != -1)
  1320.         printf("%s:%d:Unbalanced @{%s} in column %d\n",file,underlineRow,"u",underlineCol);
  1321.  
  1322.     if(boldCol != -1)
  1323.         printf("%s:%d:Unbalanced @{%s} in column %d\n",file,boldRow,"b",boldCol);
  1324.  
  1325.     if(italicsCol != -1)
  1326.         printf("%s:%d:Unbalanced @{%s} in column %d\n",file,italicsRow,"i",italicsCol);
  1327.  
  1328.     mainFound = (struct EntryNode *)FindIName(&NodeList,"main");
  1329.     if(mainFound)
  1330.         mainFound->references++;
  1331.     else
  1332.         printf("%s:%d:MAIN node missing\n",file,1);
  1333.  
  1334.     if(NOT IsListEmpty(&TocList))
  1335.     {
  1336.         struct EntryNode *found;
  1337.         int mainContext = 0;
  1338.  
  1339.         for(node = (struct EntryNode *)TocList.lh_Head ; node->Node.ln_Succ ; node = (struct EntryNode *)node->Node.ln_Succ)
  1340.         {
  1341.             found = (struct EntryNode *)FindIName(&NodeList,node->Node.ln_Name);
  1342.             if(found)
  1343.                 found->references++;
  1344.             else
  1345.             {
  1346.                 struct DatabaseNode *otherNode;
  1347.  
  1348.                 otherNode = LocateNode(parentFile,file,node->line,(char *)node->Node.ln_Name);
  1349.                 if(otherNode != NULL && Recursive && !otherNode->checked)
  1350.                 {
  1351.                     FILE *in;
  1352.  
  1353.                     in = fopen(otherNode->Node.ln_Name,"r");
  1354.                     if(in != NULL)
  1355.                     {
  1356.                         otherNode->checked = TRUE;
  1357.                         CheckGuide(otherNode->Node.ln_Name,parentFile,in);
  1358.  
  1359.                         fclose(in);
  1360.                     }
  1361.                     else
  1362.                     {
  1363.                         perror(otherNode->Node.ln_Name);
  1364.                     }
  1365.                 }
  1366.  
  1367.                 if(otherNode == NULL)
  1368.                     printf("%s:%d:TOC node \"%s\" missing\n",file,node->line,node->Node.ln_Name);
  1369.             }
  1370.  
  1371.             if(node->within == NULL)
  1372.             {
  1373.                 if(mainContext++ > 0)
  1374.                     printf("%s:%d:More than one @TOC at top level\n",file,node->line);
  1375.             }
  1376.         }
  1377.  
  1378.         FreeList(&TocList);
  1379.     }
  1380.  
  1381.     if(NOT IsListEmpty(&IndexList))
  1382.     {
  1383.         struct EntryNode *found;
  1384.         int mainContext = 0;
  1385.  
  1386.         for(node = (struct EntryNode *)IndexList.lh_Head ; node->Node.ln_Succ ; node = (struct EntryNode *)node->Node.ln_Succ)
  1387.         {
  1388.             found = (struct EntryNode *)FindIName(&NodeList,node->Node.ln_Name);
  1389.             if(found)
  1390.                 found->references++;
  1391.             else
  1392.             {
  1393.                 struct DatabaseNode *otherNode;
  1394.  
  1395.                 otherNode = LocateNode(parentFile,file,node->line,(char *)node->Node.ln_Name);
  1396.                 if(otherNode != NULL && Recursive && !otherNode->checked)
  1397.                 {
  1398.                     FILE *in;
  1399.  
  1400.                     in = fopen(otherNode->Node.ln_Name,"r");
  1401.                     if(in != NULL)
  1402.                     {
  1403.                         otherNode->checked = TRUE;
  1404.                         CheckGuide(otherNode->Node.ln_Name,parentFile,in);
  1405.  
  1406.                         fclose(in);
  1407.                     }
  1408.                     else
  1409.                     {
  1410.                         perror(otherNode->Node.ln_Name);
  1411.                     }
  1412.                 }
  1413.  
  1414.                 if(otherNode == NULL)
  1415.                     printf("%s:%d:INDEX node \"%s\" missing\n",file,node->line,node->Node.ln_Name);
  1416.             }
  1417.  
  1418.             if(node->within == NULL)
  1419.             {
  1420.                 if(mainContext++ > 0)
  1421.                     printf("%s:%d:More than one @INDEX at top level\n",file,node->line);
  1422.             }
  1423.         }
  1424.  
  1425.         FreeList(&IndexList);
  1426.     }
  1427.  
  1428.     for(node = (struct EntryNode *)NodeList.lh_Head ; node->Node.ln_Succ ; node = (struct EntryNode *)node->Node.ln_Succ)
  1429.     {
  1430.         if(node->references == 0)
  1431.             printf("%s:%d:Unused @node \"%s\"\n",file,node->line,node->Node.ln_Name);
  1432.     }
  1433.  
  1434.     FreeList(&NodeList);
  1435. }
  1436.  
  1437. /****************************************************************************/
  1438.  
  1439. int
  1440. main(int argc,char **argv)
  1441. {
  1442.     if(DOSBase->lib_Version >= 36)
  1443.     {
  1444.         if(argc > 1 && !(argc == 2 && argv[1][0] == '?'))
  1445.         {
  1446.             FILE * in;
  1447.             int i;
  1448.  
  1449.             NewList(&CheckedFileList);
  1450.  
  1451.             for(i = 1 ; i < argc ; i++)
  1452.             {
  1453.                 if(stricmp(argv[i],"-r") == SAME || stricmp(argv[i],"--recursive") == SAME)
  1454.                 {
  1455.                     Recursive = TRUE;
  1456.                     continue;
  1457.                 }
  1458.  
  1459.                 if(stricmp(argv[i],"-o") == SAME || stricmp(argv[i],"--onlyguidefiles") == SAME)
  1460.                 {
  1461.                     OnlyGuideFiles = TRUE;
  1462.                     continue;
  1463.                 }
  1464.  
  1465.                 if(stricmp(argv[i],"-w") == SAME || stricmp(argv[i],"--nowarnings") == SAME)
  1466.                 {
  1467.                     Warnings = FALSE;
  1468.                     continue;
  1469.                 }
  1470.  
  1471.                 in = fopen(argv[i],"r");
  1472.                 if(in != NULL)
  1473.                 {
  1474.                     BPTR lock;
  1475.  
  1476.                     lock = Lock(argv[i],SHARED_LOCK);
  1477.                     if(lock != NULL)
  1478.                     {
  1479.                         struct DatabaseNode *node;
  1480.  
  1481.                         node = RegisterFile(&CheckedFileList,lock);
  1482.  
  1483.                         UnLock(lock);
  1484.  
  1485.                         if(node != NULL)
  1486.                         {
  1487.                             node->checked = TRUE;
  1488.                             CollectNodes(node->Node.ln_Name,&node->nodes);
  1489.                         }
  1490.                     }
  1491.  
  1492.                     CheckGuide(argv[i],argv[i],in);
  1493.     
  1494.                     fclose(in);
  1495.                 }
  1496.                 else
  1497.                 {
  1498.                     perror(argv[i]);
  1499.                 }
  1500.             }
  1501.  
  1502.             FreeList(&CheckedFileList);
  1503.         }
  1504.         else
  1505.         {
  1506.             printf("Usage: checkguide [-r,--recursive] [-o,--onlyguidefiles] [-w,--nowarnings]\n");
  1507.             printf("                  <files>\n");
  1508.         }
  1509.     }
  1510.  
  1511.     return(0);
  1512. }
  1513.